using Android.Content;
using Android.Widget;
using Android.Views;
using SharpDepend;
using SharpDepend.Classes;
using SharpDepend.Datatypes;
using System;
using System.Collections.Generic;

namespace SharpDepend.Controls
{
    class GraphicsDisplay : LinearLayout, IGraphicsDisplay
    {
        public GraphicsDisplay()
            : base(SharpDepend.Android.Manager.Context)
        {

        }

        private IGraphicsDevice mCurrentDevice;
        private bool mReady2;
        private List<Texture> mReadyTexturesToRegistrate = new List<Texture>();
        private bool mEnable;
        private bool mRenderTextures;
        private IGraphicsDevice mManualGraphicsDevice;

        public event Action DeviceLoaded;

        public event Action DeviceUnloaded;

        public void GraphicsDeviceChanged(IGraphicsDevice device)
        {
            // Do not change if the manual graphics device is set.
            if (ManualGraphicsDevice != null)
            {
                return;
            }

            mReady2 = false;

            foreach (var texture in mReadyTexturesToRegistrate)
            {
                device.RegisterTexture(texture);
            }
            mReadyTexturesToRegistrate.Clear();

            if (mCurrentDevice != null)
            {
                // Unload textures from old device to the new one.
                for (int i = mCurrentDevice.Textures.Count - 1; i > -1; --i)
                {
                    Texture texture = mCurrentDevice.Textures[i];
                    device.RegisterTexture(texture);
                    mCurrentDevice.UnregisterTexture(texture);
                }

                // Swich properties.
                device.Enable = mCurrentDevice.Enable;
                device.RenderTextures = mCurrentDevice.RenderTextures;

                // Unload event.
                System.Action call = DeviceUnloaded;
                if (call != null)
                {
                    call();
                }

                mCurrentDevice.DisposeDevice();
                RemoveAllViews();
            }

            mCurrentDevice = device;
            AddView((View)device);
            Invalidate();

            // Load event.
            System.Action call2 = DeviceLoaded;
            if (call2 != null)
            {
                call2();
            }

            mReady2 = true;
        }

        public IGraphicsDevice GraphicsDevice
        {
            get { return mCurrentDevice; }
        }

        public event EventHandlerMouseDownAction PointDown;

        public event EventHandlerMouseAction PointMove;

        public event EventHandlerMouseAction PointUp;

        public event EventHandlerMouseWheelAction PointWheel;

        public event EventHandlerMouseAction PointHover;

        public bool OnMouseDown(ref TouchLocation location, int id, int touchCount)
        {
            var call = PointDown;
            if (call != null)
            {
                return call(ref location, id, touchCount);
            }
            return false;
        }

        public void OnMouseMove(ref TouchLocation location, int id, int touchCount)
        {
            var call = PointMove;
            if (call != null)
            {
                call(ref location, id, touchCount);
            }
        }

        public void OnMouseUp(ref TouchLocation location, int id, int touchCount)
        {
            var call = PointUp;
            if (call != null)
            {
                call(ref location, id, touchCount);
            }
        }

        public void OnMouseWheel(ref TouchLocation location)
        {
            var call = PointWheel;
            if (call != null)
            {
                call(ref location);
            }
        }

        public void OnMouseHover(ref TouchLocation location, int id, int touchCount)
        {
            var call = PointHover;
            if (call != null)
            {
                call(ref location, id, touchCount);
            }
        }
        
        public object Locker
        {
            get { return SharpDepend.Manager.GraphicsDisplayManager; }
        }

        public bool Ready
        {
            get
            {
                var gd = GraphicsDevice;
                return gd != null && gd.Ready && mReady2;
            }
        }

        public bool Enable
        {
            get
            {
                return mEnable;
            }
            set
            {
                mEnable = value;

                var g = GraphicsDevice;
                if (g != null)
                {
                    g.Enable = value;
                }
            }
        }

        public bool RenderTextures
        {
            get { return mRenderTextures; }
            set
            {
                mRenderTextures = value;

                var g = GraphicsDevice;
                if (g != null)
                {
                    g.RenderTextures = value;
                }
            }
        }

        public IGraphicsDevice ManualGraphicsDevice
        {
            get
            {
                return mManualGraphicsDevice;
            }

            set
            {
                if (mManualGraphicsDevice != value)
                {
                    if (value != null)
                    {
                        GraphicsDeviceChanged(value);
                        value.Initialize(this);
                    }

                    mManualGraphicsDevice = value;
                }
            }
        }

        public void RegisterTexture(Datatypes.Texture texture)
        {
            lock (Locker)
            {
                var device = GraphicsDevice;
                if (device != null)
                {
                    GraphicsDevice.RegisterTexture(texture);
                }
                else
                {
                    if (mReadyTexturesToRegistrate.Contains(texture))
                    {
                        throw new Exception("Texture already added.");
                    }
                    mReadyTexturesToRegistrate.Add(texture);
                }
            }
        }

        public void UnregisterTexture(Datatypes.Texture texture)
        {
            lock (Locker)
            {
                var device = GraphicsDevice;
                if (device != null)
                {
                    GraphicsDevice.UnregisterTexture(texture);
                }
                else
                {
                    if (!mReadyTexturesToRegistrate.Contains(texture))
                    {
                        throw new Exception("Texture can not be removed. It do not exist.");
                    }
                    mReadyTexturesToRegistrate.Remove(texture);
                }
            }
        }

        public bool ContainsTexture(Datatypes.Texture texture)
        {
            return GraphicsDevice.Textures.Contains(texture);
        }
    }
}